package cn.kinoko.service.common.impl;

import cn.hutool.core.util.StrUtil;
import cn.kinoko.common.code.ErrorCodeEnum;
import cn.kinoko.common.constant.HeaderConstant;
import cn.kinoko.common.model.KV;
import cn.kinoko.common.utils.BitmapUtil;
import cn.kinoko.common.utils.ExceptionUtil;
import cn.kinoko.common.utils.ThreadLocalUtil;
import cn.kinoko.mapper.common.CommonMapper;
import cn.kinoko.model.cnTeam.constant.Position;
import cn.kinoko.model.cnTeam.vo.MemberVO;
import cn.kinoko.model.cnTeam.vo.PositionTreeVO;
import cn.kinoko.model.user.entity.UserInfo;
import cn.kinoko.service.cnTeam.PositionService;
import cn.kinoko.service.common.CommonService;
import cn.kinoko.service.user.UserInfoService;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;


/**
 * 通用api
 *
 * @author kinoko
 */
@AllArgsConstructor
@Service
public class CommonServiceImpl implements CommonService {

    private UserInfoService userInfoService;
    private CommonMapper commonMapper;
    private PositionService cnPositionService;

    /**
     * 获取当前访问用户
     *
     * @return 获取当前访问用户
     */
    @Override
    public UserInfo currentUser() {
        // 获取用户id
        Long uid = (Long) ThreadLocalUtil.get(HeaderConstant.UID_HEADER);
        // 判空响应登录异常
        ExceptionUtil.isNull(uid, ErrorCodeEnum.USER_ERROR_A0230);
        UserInfo user = userInfoService.getUser(uid);
        ExceptionUtil.isNull(user, ErrorCodeEnum.USER_ERROR_A0230);
        return user;
    }

    /**
     * 查询对象
     *
     * @param aClass 实体类
     * @param bizId  业务id
     * @return 实体类
     */
    @Override
    public Map<String, Object> queryObj(Class<?> aClass, Long bizId) {
        // 获取表名
        String tableName = getTableNameStr(aClass.getAnnotation(TableName.class), aClass);
        // 获取id
        Optional<String> tableId = getTableId(aClass);
        // 查询对象，若id为空直接返回null
        return tableId.map(id -> commonMapper.findObjById(tableName, StringUtils.isBlank(id) ? "id" : id, bizId)).orElse(null);
    }

    /**
     * 查询对象
     *
     * @param aClass 实体类
     * @param bizIds 业务id
     * @return 实体类
     */
    @Override
    public List<Map<String, Object>> queryObj(Class<?> aClass, List<Long> bizIds) {
        // 获取表名
        String tableName = getTableNameStr(aClass.getAnnotation(TableName.class), aClass);
        // 获取id
        Optional<String> tableId = getTableId(aClass);
        // 查询对象，若id为空直接返回null
        return tableId.map(id -> commonMapper.findObjByIds(tableName, StringUtils.isBlank(id) ? "id" : id, bizIds)).orElse(null);
    }

    /**
     * 处理成员视图
     *
     * @param memberList 成员列表
     * @return 成员视图
     */
    @Override
    public List<MemberVO> handleMemberPosition(List<MemberVO> memberList) {
        // 查询汉化组职位
        Map<Long, String> positions = cnPositionService.queryAll(null);
        // 组装职位
        memberList.forEach(member -> {
            if (!member.getPosition().equals(Position.NORMAL_MEMBER.getCode())) {
                // 获取所有职位
                List<KV<Long, String>> positionList = Objects.requireNonNull(BitmapUtil.getAllBitAt(member.getPosition()))
                        .stream()
                        .filter(positions::containsKey)
                        .map(position -> new KV<>(position, positions.get(position)))
                        .toList();
                member.setPositionName(positionList);
            } else {
                member.setPositionName(Collections.singletonList(new KV<>(Position.NORMAL_MEMBER.getCode(), Position.NORMAL_MEMBER.getDesc())));
            }
        });
        return memberList;
    }

    /**
     * 处理漫画职位树
     *
     * @param memberList 成员列表
     * @return 职位树
     */
    @Override
    public Map<Long, PositionTreeVO> handleMangaPositionTree(List<MemberVO> memberList) {
        // 查询汉化组职位
        Map<Long, String> positionMap = cnPositionService.queryAll(null);
        // 组装职位
        Map<Long, PositionTreeVO> treeMap = new HashMap<>();
        for (MemberVO member : memberList) {
            // 获取所有职位
            List<KV<Long, String>> positionList = Objects.requireNonNull(BitmapUtil.getAllBitAt(member.getPosition()))
                    .stream()
                    .filter(positionMap::containsKey)
                    .map(position -> new KV<>(position, positionMap.get(position)))
                    .toList();
            // 分组填充
            for (KV<Long, String> kv : positionList) {
                // 存在则往分组中添加成员
                if (treeMap.containsKey(kv.getKey())) {
                    PositionTreeVO positionTreeVO = treeMap.get(kv.getKey());
                    positionTreeVO.getChildren().add(new KV<>(member.getUid(), member.getUserName()));
                } else {
                    // 不存在则初始化
                    PositionTreeVO treeVO = new PositionTreeVO();
                    treeVO.setPosition(kv.getKey());
                    treeVO.setPositionName(kv.getValue());
                    Set<KV<Long, String>> userList = new HashSet<>();
                    userList.add(new KV<>(member.getUid(), member.getUserName()));
                    treeVO.setChildren(userList);
                    treeMap.put(kv.getKey(), treeVO);
                }
            }
        }
        return treeMap;
    }

    /**
     * 清理逻辑删除数据
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void clearLogicDelData() {
        commonMapper.clearLogicDelData();
    }

    /**
     * 获取表id
     *
     * @param aClass 映射类
     * @return 表id
     */
    private static @NotNull Optional<String> getTableId(Class<?> aClass) {
        // 获取id
        return Arrays.stream(aClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(TableId.class))
                .map(field -> {
                    TableId annotation = field.getAnnotation(TableId.class);
                    if (annotation == null || StrUtil.isBlank(annotation.value())) {
                        return StrUtil.toUnderlineCase(field.getName());
                    }
                    return annotation.value();
                })
                .findAny();
    }

    /**
     * 获取表名
     *
     * @param annotation 表名注解
     * @param zClass     类名
     * @return 表名
     */
    private static @Nullable String getTableNameStr(TableName annotation, Class<?> zClass) {
        // 获取表名
        final String tableName;
        // 没有找到表名，使用类名转下划线
        if (annotation == null) {
            tableName = StrUtil.toUnderlineCase(zClass.getSimpleName());
        } else {
            tableName = annotation.value();
        }
        return tableName;
    }
}